using UnityEngine;
using System.Collections.Generic;
using LitJson;
using System;
using System.Threading;
using Framework;

namespace Network 
{
    public delegate void MsgCallback(object msg);

    public class MsgDispatcher
	{
        private Dictionary<int, MsgCallback> _msgDispatch = new Dictionary<int, MsgCallback>();

        Thread _deserializeThread;
        Channel<MsgObject> _deserializeInputChannel;
        ConcurrentQueue<MsgObject> _deserializeOutputQueue;

        public MsgDispatcher()
	    {
            _deserializeInputChannel = new Channel<MsgObject>();
            _deserializeOutputQueue = new ConcurrentQueue<MsgObject>();
            _deserializeThread = new Thread(new ThreadStart(DeserializeWorker));
            _deserializeThread.Start();
        }

        public void Destroy()
        {
            _deserializeThread.Abort();
        }
	
        public void ResetConnection(IConnection f_connection)
        {
        }
	    public void process(Queue<MsgObject> msgQueue)
	    {
            
            while(msgQueue.Count > 0)
            {
                MsgObject msgQue = msgQueue.Dequeue();
                _deserializeInputChannel.Enqueue(msgQue);
            }
                

            MsgObject msg = _deserializeOutputQueue.Dequeue();
            while(msg != null)
            {
                Dispatch(msg);
                msg = _deserializeOutputQueue.Dequeue();
            }
	    }

        public void Dispatch(MsgObject msg)
        {
            if (msg.type == MsgType.JSON_RESPONSE)
            {
                JsonData json = (JsonData)msg.m_deserializeBody;
                int requestid = (int)json["requestID"];
                Framework.CoroutineDecorator.Instance.Callback(requestid, json);
            }
            else
            {
                if (_msgDispatch.ContainsKey(msg.msgID))
                {
                    MsgCallback fn = _msgDispatch[msg.msgID];
                    if (fn != null)
                        fn(msg.m_deserializeBody);
                }
            }
        }

        void DeserializeWorker()
        {
            while (true)
            {
                try
                {
                    MsgObject msg = _deserializeInputChannel.Dequeue();
                    if (msg.type == MsgType.PB )
                    {
                        System.Type protoType;
                        if (ProtoRouter.IdToType.TryGetValue(msg.msgID, out protoType))
                            msg.m_deserializeBody = ProtoUtil.DeserializeProto(protoType, msg.msgBody);
                    }
                    else if (msg.type == MsgType.STRUCT)
                    {
                        if (SerializerRouter.Deserialier.ContainsKey(msg.msgID))
                        {
                            msg.m_deserializeBody = SerializerRouter.Deserialier[msg.msgID](msg.msgBody);
                        }
                    }
                    else if (msg.type == MsgType.JSON)
                    {
                        string jsonStr = System.Text.Encoding.UTF8.GetString(msg.msgBody);
                        msg.m_deserializeBody = JsonMapper.ToObject(jsonStr);
                    }
                    else if (msg.type == MsgType.JSON_RESPONSE)
                    {
                        int requestid = System.BitConverter.ToInt32(msg.msgBody, 0);
                        string jsonStr = System.Text.Encoding.UTF8.GetString(msg.msgBody, 4, msg.msgBody.Length - 4);
                        JsonData json = JsonMapper.ToObject(jsonStr);
                        json["requestID"] = requestid;
                        msg.m_deserializeBody = json;
                    }

                    _deserializeOutputQueue.Enqueue(msg);
                }
                catch (Exception e)
                {
                }
            }
        }
	
        public void RegistMsg(ushort id, MsgCallback f_func)
        {
            if (_msgDispatch.ContainsKey(id))
                _msgDispatch[id] += f_func;
            else
                _msgDispatch.Add(id, f_func);
        }

        public void UnregistMsg(ushort id, MsgCallback f_func)
        {
            if (_msgDispatch.ContainsKey(id))
            {
                if (f_func == null)
                {
                    _msgDispatch.Remove(id);
                }
                else
                {
                    _msgDispatch[id] -= f_func;
                }
            }
            else
                Debug.LogWarning("Unregist unknow Message : " + id.ToString());
        }
    }
}